package com.hzf.common.util;

import com.google.gson.JsonObject;
import com.hzf.common.ShalUtil;
import com.jpay.ext.kit.HashKit;
import com.jpay.ext.kit.PaymentKit;
import com.jpay.weixin.api.WxPayApiConfigKit;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import springfox.documentation.spring.web.json.Json;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.DigestException;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;


public class WeixinUtil {
    private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);

        public static final String APPID = "";
        public static final String APPSECRET = "";


        private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

        private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";

        private static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

        public static final String QUERY_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";

        public static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";

        public static final String QUN_FA_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN";

        public static final String USERLIST_URL="https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID";

        public static final String USER_URL="https://api.weixin.qq.com/sns/userinfo";


        public static final String OPENID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";

        public static final String UNIFIED_ORDER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder";

        public static final String ZHUANLIAN_URL="https://api.weixin.qq.com/cgi-bin/shorturl";
        /**
         * post请求
         *
         * @param url
         * @param outStr
         * @return
         * @throws ParseException
         * @throws IOException
         */
        public static JSONObject doPostStr(String url, String outStr) throws ParseException, IOException {
            CloseableHttpClient client = HttpClients.createDefault();

            HttpPost httpost = new HttpPost(url);
            JSONObject jsonObject = null;
            httpost.setEntity(new StringEntity(outStr, "UTF-8"));
            HttpResponse response = client.execute(httpost);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            jsonObject = JSONObject.fromObject(result);
            return jsonObject;
        }
        public static JSONObject dogetUserOpenid(String code){
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("appid", PropertiesFileUtil.getInstance("wx").get("wx_appid"));
            params.put("secret", PropertiesFileUtil.getInstance("wx").get("wx_appsecret"));
            params.put("code", code);
            params.put("grant_type", "authorization_code");
            String result = HttpUtil.doGet(OPENID_URL,params);
            JSONObject  jsonObject = JSONObject.fromObject(result);
            return  dogetUserinfo(jsonObject);
        }
        public static JSONObject dogetUserinfo(JSONObject jsonObject){
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("access_token",jsonObject.getString("access_token"));
        params.put("openid",jsonObject.getString("openid"));
        params.put("lang","zh_cn");
        String result = HttpUtil.doGet(USER_URL,params);

        jsonObject = JSONObject.fromObject(result);

        return jsonObject;
    }
    public static String dogetJsapiTicket(String nonceStr,String timestamp,String url){
        Map<String, Object> params = new HashMap<String, Object>();
        String jsapi_ticket = RedisUtil.get("jsapi_ticket");
        System.out.println(jsapi_ticket);
        params.put("jsapi_ticket",jsapi_ticket);
        params.put("noncestr",nonceStr);
        params.put("timestamp",timestamp);
        params.put("url",url);
        try{
            String signature= SHA1(params);
            return signature;

        }catch (DigestException e){
            e.printStackTrace();
        }
        return  null;
    }
  public static String urltoDurl(String url){
      Map<String, Object> params = new HashMap<String, Object>();
      params.put("access_token",RedisUtil.get("access_token"));
      params.put("action","long2short");
      params.put("long_url",url);
      String result = HttpUtil.doGet(ZHUANLIAN_URL,params);
      JSONObject jsonObject = JSONObject.fromObject(result);
      return jsonObject.getString("short_url");
  }
    /**
     * SHA1 安全加密算法
     * @param maps 参数key-value map集合
     * @return
     * @throws DigestException
     */
    public static String SHA1(Map<String,Object> maps) throws DigestException {
        //获取信息摘要 - 参数字典排序后字符串
        String decrypt = getOrderByLexicographic(maps);
        try {
            //指定sha1算法
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(decrypt.getBytes());
            //获取字节数组
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString().toUpperCase();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new DigestException("签名错误！");
        }
    }
    /**
     * 获取参数的字典排序
     * @param maps 参数key-value map集合
     * @return String 排序后的字符串
     */
    private static String getOrderByLexicographic(Map<String,Object> maps){
        System.out.println(splitParams(lexicographicOrder(getParamsName(maps)),maps));
        //jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value
        //jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value
        return splitParams(lexicographicOrder(getParamsName(maps)),maps);
    }
    /**
     *
     * 功能描述：金额字符串转换：单位元转成单分

     * @param str 传入需要转换的金额字符串
     * @return 转换后的金额字符串
     */
    public static String yuanToFen(Object o) {
        if(o == null)
            return "0";
        String s = o.toString();
        int posIndex = -1;
        String str = "";
        StringBuilder sb = new StringBuilder();
        if (s != null && s.trim().length()>0 && !s.equalsIgnoreCase("null")){
            posIndex = s.indexOf(".");
            if(posIndex>0){
                int len = s.length();
                if(len == posIndex+1){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append("00");
                }else if(len == posIndex+2){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+2)).append("0");
                }else if(len == posIndex+3){
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+3));
                }else{
                    str = s.substring(0,posIndex);
                    if(str == "0"){
                        str = "";
                    }
                    sb.append(str).append(s.substring(posIndex+1,posIndex+3));
                }
            }else{
                sb.append(s).append("00");
            }
        }else{
            sb.append("0");
        }
        str = removeZero(sb.toString());
        if(str != null && str.trim().length()>0 && !str.trim().equalsIgnoreCase("null")){
            return str;
        }else{
            return "0";
        }
    }

    public static String removeZero(String str){
        char  ch;
        String result = "";
        if(str != null && str.trim().length()>0 && !str.trim().equalsIgnoreCase("null")){
            try{
                for(int i=0;i<str.length();i++){
                    ch = str.charAt(i);
                    if(ch != '0'){
                        result = str.substring(i);
                        break;
                    }
                }
            }catch(Exception e){
                result = "";
            }
        }else{
            result = "";
        }
        return result;

    }
    /**
     * 获取参数名称 key
     * @param maps 参数key-value map集合
     * @return
     */
    private static List<String> getParamsName(Map<String,Object> maps){
        List<String> paramNames = new ArrayList<String>();
        for(Map.Entry<String,Object> entry : maps.entrySet()){
            paramNames.add(entry.getKey());
        }
        return paramNames;
    }
    /**
     * 参数名称按字典排序
     * @param paramNames 参数名称List集合
     * @return 排序后的参数名称List集合
     */
    private static List<String> lexicographicOrder(List<String> paramNames){
        Collections.sort(paramNames);
        return paramNames;
    }
    /**
     * 拼接排序好的参数名称和参数值
     * @param paramNames 排序后的参数名称集合
     * @param maps 参数key-value map集合
     * @return String 拼接后的字符串
     */
    private static String splitParams(List<String> paramNames,Map<String,Object> maps){
        StringBuilder paramStr = new StringBuilder();
        for(String paramName : paramNames){
            paramStr.append(paramName);
            for(Map.Entry<String,Object> entry : maps.entrySet()){
                if(paramName.equals(entry.getKey())){
                    paramStr.append("="+String.valueOf(entry.getValue())+"&");
                }
            }
        }
        paramStr.deleteCharAt(paramStr.length()-1);
        return paramStr.toString();
    }
    public static Map<String, String> prepayIdCreateSign(String prepay_id) {
        Map<String, String> packageParams = new HashMap();
        packageParams.put("appId", PropertiesFileUtil.getInstance("wx").get("wx_appid"));
        packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
        packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
        packageParams.put("package", "prepay_id=" + prepay_id);
        packageParams.put("signType", "MD5");
        String packageSign = createSign(packageParams, "EYZHrw8oTEnJFTAXDqPt6Onjg8umV2mR");
        packageParams.put("paySign", packageSign);
        return packageParams;
    }
    public static String toPaySign(Map<String, String> map) throws Exception{
        String uuid = getRandomString(32);
        String requestXml =getRequestXml(map);//生成Xml格式的字符串
        String result = CommonUtil.httpsRequest   (UNIFIED_ORDER_URL, "POST", requestXml);//以post请求的方式调用统一下单接口
      /*  Map map1 = XMLUtil.doXMLParse(result);
        String return_code=(String) map1.get("return_code");
        String prepay_id =null;
        String returnSign=null;
        String returnNonce_str=null;
        long second = System.currentTimeMillis() / 1000L;
        String seconds = String.valueOf(second).substring(0, 10);
        if (return_code.contains("SUCCESS")){
            prepay_id=(String) map1.get("prepay_id");//获取到prepay_id
        }
        System.out.println(map1.toString());
        WxPay wxPay = new WxPay();
        wxPay.setAppid(PropertiesFileUtil.getInstance("wx").get("wx_appid"));
        wxPay.setNoncestr(uuid);
        wxPay.setPackageType("Sign=WXPay");
        wxPay.setPartnerid("1357612802");
        wxPay.setPrepayid(prepay_id);
        wxPay.setTimestamp(seconds);
        SortedMap<String, String> signParam = new TreeMap<String, String>();
        signParam.put("appid", PropertiesFileUtil.getInstance("wx").get("wx_appid"));//app_id
        signParam.put("partnerid", "1357612802");//微信商户账号
        signParam.put("prepayid", prepay_id);//预付订单id
        signParam.put("package", "Sign=WXPay");//默认sign=WXPay
        signParam.put("noncestr", uuid);//自定义不重复的长度不长于32位
        signParam.put("timestamp",seconds);//北京时间时间戳
        String signAgain = createSign("UTF-8", signParam,"EYZHrw8oTEnJFTAXDqPt6Onjg8umV2mR");//再次生成签名
        wxPay.setSign(signAgain);

        signParam.put("sign", signAgain);
        System.out.println(wxPay.getAppid());*/
        return result;
    }
    public static String getRandomString(int length) { //length表示生成字符串的长度
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    public static String createSign(Map<String, String> params, String partnerKey) {
        params.remove("sign");
        String stringA = PaymentKit.packageSign(params, false);
        String stringSignTemp = stringA + "&key=" + partnerKey;
        return HashKit.md5(stringSignTemp).toUpperCase();
    }
    //定义签名，微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序
    public static String createSign(String characterEncoding,SortedMap<String,String> parameters,String key){
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" +key);//最后加密时添加商户密钥，由于key值放在最后，所以不用添加到SortMap里面去，单独处理，编码方式采用UTF-8
        String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

//将封装好的参数转换成Xml格式类型的字符串

    public static String getRequestXml(Map<String,String> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if("sign".equalsIgnoreCase(k)){

            }
            else if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)) {
                sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
            }
            else {
                sb.append("<"+k+">"+v+"</"+k+">");
            }
        }
        sb.append("<"+"sign"+">"+"<![CDATA["+parameters.get("sign")+"]]></"+"sign"+">");
        sb.append("</xml>");
        return sb.toString();
    }




    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

        }




